﻿using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;


using DotNetNuke.Entities.Users;
using DotNetNuke.Entities.Modules;
using DotNetNuke.UI.UserControls;
using DotNetNuke.Modules.HTMLEditorProvider;
using DotNetNuke.Services.Localization;


namespace Findy.XsltDb
{
    public partial class DesktopModules_XsltDb_SettingsHost : System.Web.UI.UserControl, IModuleSettingsControl
    {
        /// //////////////////////////////////////////////////////////
        ModuleSettingsBase getModule()
        {
            return this.Parent as ModuleSettingsBase;
        }
        UserInfo UserInfo { get { return getModule().UserInfo; } }
        /// //////////////////////////////////////////////////////////

        Dictionary<string, HtmlEditorProvider> editors = new Dictionary<string, HtmlEditorProvider>();
        Dictionary<string, TableRow> rows = new Dictionary<string, TableRow>();
        XmlDocument doc = null;
        string resourcePath = "~/DesktopModules/XsltDb/App_LocalResources/Settings.ascx";
        protected void Page_Init(object sender, EventArgs e)
        {
            chHideButtons.Text = XsltDbResX.Localize("chHideButtons.Text", resourcePath);
            litHideButtonsDesc.Text = XsltDbResX.Localize("chHideButtonsDesc.Text", resourcePath);
            string html = string.Empty;
            try
            {
                doc = GetForm();
                if (doc != null)
                {
                    SectionHeadControl c = (SectionHeadControl)this.Parent.Parent.FindControl("dshSpecific");
                    string sectionCaption = GetValue(doc, "//section").Trim();
                    if (c != null && sectionCaption.Length > 0)
                        c.Text = sectionCaption;

                    if (doc.SelectNodes("//setting").Count == 0)
                        Controls.Add(new LiteralControl(XsltDbResX.Localize("noSettings.Text", resourcePath)));

                    Table t = new Table();
                    t.Width = Unit.Parse("100%");

                    foreach (XmlNode node in doc.SelectNodes("/root/setting|/root/new-group|/root/a|/root/markup"))
                    {
                        string type = GetValue(node, "@type");
                        string name = GetValue(node, "@name");

                        TableRow tr = new TableRow();
                        t.Rows.Add(tr);
                        rows[name] = tr;
                        if (node.Name == "new-group")
                        {
                            TableCell ttc = new TableCell();
                            ttc.ColumnSpan = 2;
                            ttc.Text = "<hr/>";
                            tr.Cells.Add(ttc);
                            continue;
                        }
                        if (node.Name == "a")
                        {
                            TableCell ttc = new TableCell();
                            ttc.ColumnSpan = 2;
                            ttc.Text = node.OuterXml;
                            tr.Cells.Add(ttc);
                            continue;
                        }
                        if (node.Name == "markup")
                        {
                            TableCell ttc = new TableCell();
                            ttc.ColumnSpan = 2;
                            ttc.Text = node.InnerText;
                            tr.Cells.Add(ttc);
                            continue;
                        }

                        string caption = GetValue(node, "caption");

                        TableCell tc = new TableCell();
                        bool oneCell = type == "richtext" || caption.Length == 0;
                        if (!oneCell)
                            tc.Width = Unit.Parse(GetValue(doc, "//section/@label-width"));

                        if (caption.Length > 0)
                        {
                            string appPath = Request.ApplicationPath;
                            if (appPath == "/") appPath = "";
                            HtmlGenericControl span = new HtmlGenericControl("span");
                            span.InnerHtml = (type == "richtext" ? "<br/>" : "") +
                                "<b><img src='" + appPath + "/images/help.gif' /> " +
                                HttpUtility.HtmlEncode(GetValue(node, "caption")) + "</b>";

                            span.Attributes.Add("title", GetValue(node, "tooltip"));
                            tc.Controls.Add(span);
                        }
                        if (!oneCell)
                        {
                            tr.Cells.Add(tc);
                            tc = new TableCell();
                        }
                        else
                            tc.ColumnSpan = 2;
                        Control ctr = CreateControl(node);
                        if (ctr is WebControl)
                        {
                            string localWidth = GetValue(node, "@width");
                            string width = localWidth;
                            if (width.Length == 0)
                                width = GetValue(doc, "//section/@control-width");
                            width = width.Trim();
                            if (width.EndsWith(";"))
                                width = width.Substring(0, width.Length - 1).Trim();
                            ((WebControl)ctr).Width = oneCell ? (localWidth.Length == 0 ? Unit.Percentage(100) : Unit.Parse(width)) : Unit.Parse(width);

                            string localHeight = GetValue(node, "@height");
                            if (localHeight.Length > 0)
                                ((WebControl)ctr).Height = Unit.Parse(localHeight);
                        }
                        tc.Controls.Add(ctr);
                        tc.Controls.Add(new LiteralControl("<br/>"));
                        foreach (XmlNode v in node.SelectNodes("validator"))
                        {
                            BaseValidator validator = null;

                            if (GetValue(v, "@type") == "required")
                            {
                                validator = new RequiredFieldValidator();
                            }
                            if (GetValue(v, "@type") == "range")
                            {
                                RangeValidator vld = new RangeValidator();
                                vld.MinimumValue = GetValue(v, "@min");
                                vld.MaximumValue = GetValue(v, "@max");
                                string dataType = GetValue(v, "@data-type");
                                if (dataType.Length > 0)
                                    vld.Type = (ValidationDataType)Enum.Parse(typeof(ValidationDataType), dataType);
                                validator = vld;
                            }
                            if (GetValue(v, "@type") == "compare")
                            {
                                CompareValidator vld = new CompareValidator();
                                vld.ControlToCompare = GetValue(v, "compare-to");
                                vld.Operator = (ValidationCompareOperator)Enum.Parse(typeof(ValidationCompareOperator), GetValue(v, "operator"));
                                string dataType = GetValue(v, "@data-type");
                                if (dataType.Length > 0)
                                    vld.Type = (ValidationDataType)Enum.Parse(typeof(ValidationDataType), dataType);
                                validator = vld;
                            }
                            if (GetValue(v, "@type") == "regex")
                            {
                                RegularExpressionValidator vld = new RegularExpressionValidator();
                                vld.ValidationExpression = GetValue(v, "@regex");
                                validator = vld;
                            }
                            if (validator != null)
                            {
                                validator.ControlToValidate = ctr.ID;
                                validator.Text = GetValue(v, "text()");
                                validator.Display = ValidatorDisplay.Dynamic;
                                validator.SetFocusOnError = true;
                                tc.Controls.Add(validator);
                            }
                        }
                        tr.Cells.Add(tc);
                    }
                    phSettings.Controls.Add(t);
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException is RedirectException)
                {
                    Response.Redirect((ex.InnerException as RedirectException).URL, true);
                    Response.End();
                    return;
                }
                if (UserInfo.IsInRole("Administrators") || UserInfo.IsSuperUser)
                    Controls.Add(new LiteralControl(XsltDbUtils.GetExceptionMessage(ex)));
                XsltDbUtils.WriteLog(ex);
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            ModuleInfo mi = new ModuleController().GetModule(getModule().ModuleId,getModule().TabId);
            if ( (!UserInfo.IsSuperUser) || (mi.DesktopModule.ModuleName != "XsltDb") )
                Controls.Remove(FindControl("hider"));
            else
            {
                ModuleController mc = new ModuleController();
                if ((mc.GetModuleSettings(getModule().ModuleId)["XsltDb.EditorEnabled"] ?? String.Empty).ToString() == "False")
                    Controls.Remove(FindControl("hider"));
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (IsPostBack)
            {
                Hashtable t = new Hashtable();
                foreach (DictionaryEntry de in getModule().ModuleSettings)
                    t[de.Key] = de.Value;
                if (doc != null)
                {
                    foreach (XmlNode setting in doc.SelectNodes("//setting"))
                    {
                        string name = GetValue(setting, "@name");
                        string type = GetValue(setting, "@type");
                        t[name] = GetControlValue(name, type);
                    }
                }
                Context.Items["TempModuleSettings"] = t;
            }
            doc = GetForm();
            foreach (XmlNode node in doc.SelectNodes("//setting[@type='select']"))
                UpdateDataSource(node);

            foreach (XmlNode node in doc.SelectNodes("/root/setting|/root/new-group|/root/a|/root/markup"))
            {
                string name = GetValue(node, "@name");
                if (name.Length > 0)
                    rows[name].Visible = GetValue(node, "@visible").ToLower() != "false";
            }
            base.OnPreRender(e);
        }

        Dictionary<string, bool> dsUpdated = new Dictionary<string, bool>();

        public void UpdateDataSource(XmlNode setting)
        {
            string name = GetValue(setting, "@name");
            string type = GetValue(setting, "@type");
            if (dsUpdated.ContainsKey(name)) return;
            DropDownList list = (DropDownList)FindControl(name);
            string selected = list.SelectedValue;
            list.Items.Clear();
            foreach (XmlNode n in setting.SelectNodes("source/option"))
                list.Items.Add(new ListItem(GetValue(n, "text()"), GetValue(n, "@value")));
            foreach (ListItem item in list.Items)
                if (item.Value == selected)
                    item.Selected = true;

            dsUpdated.Add(name, true);
        }

        public void LoadSettings()
        {
            if (doc == null) doc = GetForm();
            foreach (XmlNode node in doc.SelectNodes("//setting"))
            {
                string name = GetValue(node, "@name");
                string type = GetValue(node, "@type");
                if (type == "select")
                    UpdateDataSource(node);
                SetControlValue(name, type, (getModule().ModuleSettings[name] ?? string.Empty).ToString());
            }
        }

        public void UpdateSettings()
        {
            ModuleController mc = new ModuleController();
            if (doc == null) doc = GetForm();
            foreach (XmlNode node in doc.SelectNodes("//setting"))
            {
                string name = GetValue(node, "@name");
                string type = GetValue(node, "@type");
                mc.UpdateModuleSetting(getModule().ModuleId, name, GetControlValue(name, type));
            }
            if ("False" != (mc.GetModuleSettings(getModule().ModuleId)["XsltDb.EditorEnabled"] ?? string.Empty).ToString())
                mc.UpdateModuleSetting(getModule().ModuleId, "XsltDb.EditorEnabled", (!chHideButtons.Checked).ToString());
        }

        XmlDocument GetForm()
        {
            string html = string.Empty;
            XsltDbUtils.aConfig config = XsltDbUtils.GetConfig(getModule().ModuleId, getModule().TabId);
            if (config != null && config.ActiveXslt.Length > 0)
            {
                Transformer t = new Transformer(getModule());
                t.TrueHost = this;
                t.Config = config;
                html = t.GetSettingsForm(config.ActiveXslt, config.IsSuper);
            }
            XmlDocument doc = new XmlDocument();
            html = Regex.Replace(html, "<markup>(.*?)</markup>", delegate(Match mm)
            {
                return "<markup>" + Server.HtmlEncode(mm.Groups[1].Value) + "</markup>";
            }, RegexOptions.Singleline);
            doc.LoadXml("<root>" + html + "</root>");
            return doc;
        }

        public Control CreateControl(XmlNode setting)
        {
            string type = GetValue(setting, "@type");
            switch (type)
            {
                case "date": return CreateDateBox(setting);
                case "text": return CreateTextBox(setting);
                case "password": return CreatePasswordBox(setting);
                case "longtext": return CreateTextArea(setting);
                case "richtext": return CreateTextEditor(setting);
                case "checkbox": return CreateCheckBox(setting);
                case "select": return CreateSelect(setting);
                case "file": return CreateSelectFile(setting);
                default: { throw new Exception("Setting type '" + type + "' is incorrect."); }
            }
        }

        public Control CreateDateBox(XmlNode setting)
        {
            Control c = LoadControl("dtp.ascx");
            c.ID = GetValue(setting, "@name");
            if (GetValue(setting, "@auto-post-back").ToLower() == "true")
                ((IDTP)c).AutoPostBack = true;
            return c;
        }

        public Control CreateTextBox(XmlNode setting)
        {
            TextBox c = new TextBox();
            c.ID = GetValue(setting, "@name");
            if (GetValue(setting, "@auto-post-back").ToLower() == "true")
                c.AutoPostBack = true;
            return c;
        }

        public Control CreateTextArea(XmlNode setting)
        {
            TextBox c = new TextBox();
            c.ID = GetValue(setting, "@name");
            c.TextMode = TextBoxMode.MultiLine;
            if (GetValue(setting, "height").Length == 0)
                c.Rows = 6;
            if (GetValue(setting, "@auto-post-back").ToLower() == "true")
                c.AutoPostBack = true;
            return c;
        }

        public Control CreatePasswordBox(XmlNode setting)
        {
            TextBox c = new TextBox();
            c.ID = GetValue(setting, "@name");
            c.TextMode = TextBoxMode.Password;
            if (GetValue(setting, "@auto-post-back").ToLower() == "true")
                c.AutoPostBack = true;
            return c;
        }

        public Control CreateTextEditor(XmlNode setting)
        {
            HtmlEditorProvider c = HtmlEditorProvider.Instance();
            c.ControlID = GetValue(setting, "@name");
            c.Initialize();
            editors[c.ControlID] = c;
            return c.HtmlEditorControl;
        }

        public Control CreateCheckBox(XmlNode setting)
        {
            CheckBox c = new CheckBox();
            c.ID = GetValue(setting, "@name");
            if (GetValue(setting, "@auto-post-back").ToLower() == "true")
                c.AutoPostBack = true;
            return c;
        }

        public Control CreateSelectFile(XmlNode setting)
        {
            object fe = Activator.CreateInstance("DotNetNuke.Web", "DotNetNuke.Web.UI.WebControls.DnnFileEditControl").Unwrap();
            Control fec = (Control)fe;
            fec.ID = GetValue(setting, "@name");
            string ps = GetValue(setting, "@include-personal-folder");
            if (ps.Length > 0)
                fe.GetType().GetProperty("IncludePersonalFolder").SetValue(fe,
                    Convert.ToBoolean(ps), new object[] { });
            string filter = GetValue(setting, "@filter");
            if (filter.Length > 0)
                fe.GetType().GetProperty("FileFilter").SetValue(fe, filter, new object[] { });
            return fec;
        }

        public Control CreateSelect(XmlNode setting)
        {
            DropDownList list = new DropDownList();
            list.ID = GetValue(setting, "@name");
            if (GetValue(setting, "@auto-post-back").ToLower() == "true")
                list.AutoPostBack = true;
            return list;
        }

        string GetValue(XmlNode source, string xpath)
        {
            XmlNode res = source.SelectSingleNode(xpath);

            if (res == null)
                return string.Empty;
            if (res is XmlAttribute)
                return ((XmlAttribute)res).Value;
            if (res is XmlText)
                return ((XmlText)res).Value;
            else
                return ((XmlElement)res).InnerText;
        }

        public string GetControlValue(string name, string type)
        {
            Control c = FindControl(name);
            if (c is TextBox)
                return ((TextBox)c).Text;
            if (c is CheckBox)
                return ((CheckBox)c).Checked.ToString();
            if (c is DropDownList)
                return ((DropDownList)c).SelectedValue;
            if (type == "richtext")
                return editors.ContainsKey(name) ? editors[name].Text : string.Empty;
            if (type == "file")
                return c.GetType().GetProperty("Value").GetValue(c, new object[] { }).ToString();
            if (type == "date")
                return ((IDTP)c).Value;
            return string.Empty;
        }
        public void SetControlValue(string name, string type, string value)
        {
            Control c = FindControl(name);
            if (c is TextBox)
                ((TextBox)c).Text = value;
            if (c is CheckBox)
            {
                bool val;
                if (bool.TryParse(value, out val))
                    ((CheckBox)c).Checked = val;
            }
            if (c is DropDownList)
            {
                DropDownList lst = (DropDownList)c;
                foreach (ListItem item in lst.Items)
                    if (item.Value == value)
                        item.Selected = true;
            }
            if (type == "richtext" && editors.ContainsKey(name))
                editors[name].Text = value;
            if (type == "file")
                c.GetType().GetProperty("Value").SetValue(c, value, new object[] { });
            if (type == "date")
                ((IDTP)c).Value = value;
        }
    }
}